package cn.kgc.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.kgc.entity.Menus;
import cn.kgc.entity.Roles;
import cn.kgc.entity.Users;
import cn.kgc.form.RolesAddForm;
import cn.kgc.service.MenusService;
import cn.kgc.service.RolesService;
import cn.kgc.service.UsersService;
import cn.kgc.util.Pager;
import cn.kgc.util.resultutil.ResultConstant;
import cn.kgc.util.resultutil.exception.HttpException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author YC
 */
@RestController
@RequestMapping("/roles")
@Api(tags = "角色管理接口")
@Validated
@Slf4j
@CrossOrigin
public class RolesController {

    @Resource
    private RolesService rolesService;
    @Resource
    private UsersService usersService;
    @Resource
    private MenusService menusService;

    /**
     * 查询所有数据
     *
     * @return 信息集合
     */
    @GetMapping("/list")
    @ApiOperation(value = "查询所有角色信息")
    @Cacheable(value = "roles#360", key = "#root.methodName")
    @CrossOrigin
    public List<Roles> selectAll() {
        return rolesService.list();
    }

    /**
     * 分页查询角色信息
     *
     * @param map 查询参数（currentPage pageSize roleName）
     * @return 封装结果实例
     */
    @PostMapping("/page")
    @ApiOperation(value = "分页查询角色信息")
    @CrossOrigin
    public Pager<Roles> selectPage(@RequestBody HashMap<String, Object> map) {
        int currentPage = MapUtil.getInt(map, "currentPage");
        int pageSize = MapUtil.getInt(map, "pageSize");
        String roleName = MapUtil.getStr(map, "roleName");

        LambdaQueryWrapper<Roles> wrapper = new LambdaQueryWrapper<>();
        wrapper.likeRight(StrUtil.isNotBlank(roleName), Roles::getRoleName, roleName);
        Page<Roles> page = new Page<>(currentPage, pageSize);
        return Pager.build(rolesService.page(page, wrapper));
    }

    @GetMapping("/detail/{id}")
    @ApiOperation(value = "查看详细信息")
    @Cacheable(value = "roles#360", key = "#root.methodName + #id")
    @CrossOrigin
    public Roles selectOne(@PathVariable Serializable id) {
        return this.rolesService.getById(id);
    }

    @DeleteMapping("/delete/{id}")
    @ApiOperation(value = "删除角色信息")
    @ApiImplicitParam(name = "id", value = "主键", paramType = "path", dataType = "string")
    @Caching(evict = {
            @CacheEvict(value = "roles", key = "'selectAll'"),
            @CacheEvict(value = "roles", key = "'selectOne' + #id"),
            @CacheEvict(key = "'system:authorities:' + #id")
    })
    @CrossOrigin
    public boolean delete(@PathVariable Integer id) {
        // 被引用的角色不能删除
        checkRoleIsUsed(id);
        // 删除角色及对应的菜单
        return rolesService.deleteRolesById(id);
    }

    @PostMapping("/save")
    @ApiOperation(value = "新增角色信息")
    @CacheEvict(value = "roles", key = "'selectAll'")
    public boolean save(@RequestBody RolesAddForm form) {
        // 角色名称重复不能新增
        checkRoleName(form.getRoleName());
        Roles roles = new Roles();
        BeanUtil.copyProperties(form, roles);
        return rolesService.save(roles);
    }

    @GetMapping("/all/menus/{roleId}")
    @ApiOperation(value = "查询角色以及对应的所有菜单")
    public Map<String, List<Menus>> menus(@PathVariable Integer roleId) {
        // 查询所有菜单
        List<Menus> allMenus = menusService.list();
        // 查询角色拥有的菜单（前端使用的是El树形选择器，选择父级会全选子菜单，所以后端返回信息中应该不包含任何的父级菜单）
        List<Menus> roleMenus = menusService.selectAllMenusByRoleId(roleId);
        return Map.of("allMenus", allMenus, "roleMenus", roleMenus);
    }

    /**
     * 更新角色拥有的菜单
     */
    @PostMapping("/update")
    @ApiOperation(value = "更新角色拥有的菜单")
    @CacheEvict(key = "'system:authorities:' + #map.get('roleId')")
    public boolean update(@RequestBody Map<String, Object> map) {
        return rolesService.updateRolesMenus(map);
    }


//============================= 角色管理接口自定义方法 ===========================

    private void checkRoleIsUsed(Integer id) {
        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Users::getRoleId, id);
        if (usersService.count(wrapper) > 0) {
            throw new HttpException(ResultConstant.ROLE_DELETE_ERROR_USED);
        }
    }

    private void checkRoleName(String roleName) {
        LambdaQueryWrapper<Roles> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Roles::getRoleName, roleName);
        if (rolesService.count(wrapper) > 0) {
            throw new HttpException(ResultConstant.ROLE_UPDATE_ERROR_REPEAT);
        }
    }

}
